package com.qijian.maindata.controller;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qijian.common.annotation.Excel;
import com.qijian.common.annotation.Log;
import com.qijian.common.core.controller.BaseController;
import com.qijian.common.core.domain.AjaxResult;
import com.qijian.common.core.page.TableDataInfo;
import com.qijian.common.enums.ApprovalDescriptionEnum;
import com.qijian.common.enums.BusinessType;
import com.qijian.common.exception.ServiceException;
import com.qijian.common.utils.StringUtils;
import com.qijian.common.utils.mybatis.WhereEntityTool;
import com.qijian.common.utils.poi.ExcelUtil;
import com.qijian.common.utils.uuid.IdUtils;
import com.qijian.maindata.domain.Item;
import com.qijian.maindata.domain.ProductAttribute;
import com.qijian.maindata.domain.ProductAttributeItem;
import com.qijian.maindata.domain.dto.ItemDto;
import com.qijian.maindata.domain.dto.ItemSaleDto;
import com.qijian.maindata.domain.query.ItemQuery;
import com.qijian.maindata.domain.query.ProductAttributeQuery;
import com.qijian.maindata.domain.vo.ItemVo;
import com.qijian.maindata.service.IItemService;
import com.qijian.maindata.service.IProductAttributeService;
import com.qijian.tool.domain.Storage;
import com.qijian.tool.domain.query.StorageQuery;
import com.qijian.tool.service.IStorageService;
import io.swagger.annotations.Api;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 物料档案Controller
 *
 * @author qijian
 * @date 2021-09-01
 */
@Api(tags = "工艺管理：物料档案")
@RestController
@RequiredArgsConstructor
@RequestMapping("/maindata/item")
public class ItemController extends BaseController {

    private final IItemService itemService;
    private final IStorageService storageService;

    private final IProductAttributeService productAttributeService;

    /**
     * 查询物料档案列表
     */
//    @PreAuthorize("@ss.hasAnyPermi('maindata:item:list,business:eqp:list,business:mtTicket:list')")
    @GetMapping("/list")
    public TableDataInfo list(ItemQuery query, Page<Item> page) {
        return getDataTable(itemService.pageVo(page, WhereEntityTool.invoke(query)));
    }

    /**
     * 导出物料档案列表
     */
    @PreAuthorize("@ss.hasPermi('maindata:item:export')")
    @Log(title = "物料档案", businessType = BusinessType.EXPORT)
    @GetMapping("/export")
    public AjaxResult export(ItemQuery query) {
        return new ExcelUtil<>(Item.class).exportExcel(itemService.list(WhereEntityTool.invoke(query)), "物料档案数据");
    }


    /**
     * 物料检验模板
     */
    @GetMapping("/importCheckTemplate")
    public AjaxResult importCheckTemplate(@RequestParam(value = "type", required = false) String type) {
        if ("XSBJ".equals(type)) {
            return new ExcelUtil<>(ItemSaleDto.class).importTemplateExcel("物料导入");
        }
        return new ExcelUtil<>(ItemDto.class).importTemplateExcel("物料导入");
    }

    /**
     * 物料检验数据导入
     * 1.销售管理>销售报价>新增>>工艺>导入
     */
    @PostMapping("/importCheck")
    public AjaxResult importData(MultipartFile file) throws Exception {
        List<ItemDto> list = new ExcelUtil<>(ItemDto.class).importExcel(file.getInputStream());
        List<ItemDto> result = new ArrayList<>(list.size());
        ItemQuery query = new ItemQuery();
        query.setItemCodeList(list.stream().map(action -> (String) ReflectUtil.getFieldValue(action, "itemCode")).collect(Collectors.toList()));
        Map<String, Item> itemMap = itemService.list(WhereEntityTool.invoke(query)).stream().collect(Collectors.toMap(Item::getItemCode, a -> a));
        list.forEach(action -> {
            Map<String, Object> itemAttr = new HashMap<>(20);
            Map<String, Field> fieldMap = ReflectUtil.getFieldMap(action.getClass());
            String itemCode = (String) ReflectUtil.getFieldValue(action, "itemCode");
            Item item = itemMap.get(itemCode);
            if (item != null) {
                fieldMap.forEach((key, value) -> {
                    if (value != null && value.getAnnotation(Excel.class) != null) {
                        String name = value.getAnnotation(Excel.class).name();
                        if (name.contains("辅助属性.")) {
                            String val = (String) ReflectUtil.getFieldValue(action, key);
                            if (StringUtils.isNotBlank(val) && !"/".equals(val)) {
                                itemAttr.put(name.split("\\.")[1], ReflectUtil.getFieldValue(action, key));
                            }
                            ReflectUtil.setFieldValue(action, key, null);
                        }
                    }
                });
                action.setItemAttr(JSONUtil.toJsonStr(itemAttr));
                ReflectUtil.setFieldValue(action, "itemId", item.getItemId());
                ReflectUtil.setFieldValue(action, "itemName", item.getItemName());
                result.add(action);
            }
        });
        return AjaxResult.success(result);
    }

    /**
     * 获取物料档案详细信息
     */
    @PreAuthorize("@ss.hasPermi('maindata:item:query')")
    @GetMapping(value = "/{itemId}")
    public AjaxResult getInfo(@PathVariable("itemId") Long itemId) {
        return AjaxResult.success(itemService.getById(itemId));
    }

    /**
     * 物料档案提交审核
     */
    @Log(title = "物料", businessType = BusinessType.APPROVAL)
//    @PreAuthorize("@ss.hasPermi('maindata:item:approval')")
    @GetMapping(value = "/approval/{itemId}")
    public AjaxResult approval(@PathVariable("itemId") Long itemId) {
        Item item = itemService.getById(itemId);
        if (ObjectUtil.isNull(item)) {
            throw new ServiceException("E01:单据信息错误！");
        } else if (item.getApprovalStatus() == ApprovalDescriptionEnum.B) {
            throw new ServiceException("E01:单据审核中！");
        } else if (item.getApprovalStatus() == ApprovalDescriptionEnum.C) {
            throw new ServiceException("E01:单据已审核！");
        }
        Item itemChange = new Item();
        itemChange.setItemId(itemId);
        itemChange.setApprovalStatus(ApprovalDescriptionEnum.B);
        return AjaxResult.success(itemService.updateById(itemChange));
    }

    /**
     * 单据审核通过
     */
    @Log(title = "物料", businessType = BusinessType.APPROVAL)
    @PreAuthorize("@ss.hasPermi('maindata:item:approved')")
    @GetMapping(value = "/approved/{itemId}")
    public AjaxResult approved(@PathVariable("itemId") Long itemId) {
        Item item = itemService.getById(itemId);
        if (ObjectUtil.isNull(item) || item.getApprovalStatus() == ApprovalDescriptionEnum.C) {
            throw new ServiceException("E01:单据已审核！");
        }
        Item itemChange = new Item();
        itemChange.setItemId(itemId);
        itemChange.setApprovalStatus(ApprovalDescriptionEnum.C);
        return AjaxResult.success(itemService.updateById(itemChange));
    }

    /**
     * 单据反审核
     */
    @Log(title = "物料", businessType = BusinessType.APPROVAL)
    @PreAuthorize("@ss.hasPermi('maindata:item:deApproval')")
    @GetMapping(value = "/deApproval/{itemId}")
    public AjaxResult deApproval(@PathVariable("itemId") Long itemId) {
        Item itemChange = new Item();
        itemChange.setItemId(itemId);
        itemChange.setApprovalStatus(ApprovalDescriptionEnum.D);
        return AjaxResult.success(itemService.updateById(itemChange));
    }

    /**
     * 新增单据
     */
    @PreAuthorize("@ss.hasPermi('maindata:item:add')")
    @Log(title = "单据", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody ItemVo itemVo) {
        itemVo.setApprovalStatus(ApprovalDescriptionEnum.A);
        return toAjax(save(itemVo));
    }

    /**
     * 修改单据
     */
    @PreAuthorize("@ss.hasPermi('maindata:item:edit')")
    @Log(title = "单据", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody ItemVo itemVo) {
        Item item = itemService.getById(itemVo.getItemId());
        if (ObjectUtil.isNull(item)) {
            throw new ServiceException("E01:单据信息错误！");
        } else if (item.getApprovalStatus() == ApprovalDescriptionEnum.B) {
            throw new ServiceException("E01:单据审核中，无法修改！");
        } else if (item.getApprovalStatus() == ApprovalDescriptionEnum.C) {
            throw new ServiceException("E01:单据已审核，无法修改！");
        }
        return toAjax(save(itemVo));
    }

    @Transactional(rollbackFor = Exception.class)
    boolean save(ItemVo itemVo) {
        Item resource = JSONUtil.parse(itemVo).toBean(Item.class);
        ProductAttributeQuery query = new ProductAttributeQuery();
        List<ProductAttribute> data = productAttributeService.list(WhereEntityTool.invoke(query));
        resource.setApprovalStatus(null);
        if (ObjectUtil.isNull(resource.getItemId())) {
            resource.setItemId(IdUtils.singletonSnowId());
        }
        //对物料属性重新排序
        if (itemVo.getItemAttr() != null && itemVo.getItemAttr().length() > 0) {
            //jsonArray 按照对象属性排序
            JSONArray objects = JSONUtil.parseArray(itemVo.getItemAttr());
            JSONArray jsonArray = new JSONArray();

            if (CollectionUtils.isNotEmpty(data)) {
                data.stream().forEach(e->{
                    objects.forEach(o->{
                        JSONObject jsonObject = JSONUtil.parseObj(o);
                        if (jsonObject.getStr("name") !=null && jsonObject.getStr("name").equals(e.getName())) {
                            jsonArray.put(jsonObject);
                        }
                    });
                });
                resource.setItemAttr(jsonArray.toString());
            }
        }
//        Long count = itemService.lambdaQuery().eq(Item::getItemCode, itemVo.getItemCode())
//                .ne(ObjectUtil.isNull(resource.getItemId()), Item::getItemId, itemVo.getItemId()).count();
        Long count = itemService.lambdaQuery().eq(Item::getItemCode, itemVo.getItemCode())
            .ne(Item::getItemId, resource.getItemId()).count();
        if (count>0){
            throw new ServiceException("E01:物料编号重复");
        }
        // 文件来源更新
        if (ObjectUtil.isNotEmpty(itemVo.getStorage()) && ObjectUtil.isNotEmpty(itemVo.getStorage().getStorageId())) {
            StorageQuery storageQuery = new StorageQuery();
            storageQuery.setStorageId(itemVo.getStorage().getStorageId());
            Storage storage = new Storage();
            storage.setClassTable(Item.class.getSimpleName());
            storage.setClassId(resource.getItemId());
            storageService.update(storage, WhereEntityTool.invoke(storageQuery));
        }
        if (itemVo.getAttrItems() != null) {
            itemVo.getAttrItems().forEach(ai -> {
                ai.setItemId(resource.getItemId());
                ai.setItemName(resource.getItemName());
                ai.setItemCode(resource.getItemCode());
            });
            cleanDetailsData(resource.getItemId(), itemVo.getAttrItems(), ProductAttributeItem.class);
        }

        if (ObjectUtil.isNull(itemVo.getItemId())) {
            itemService.save(resource);
        } else {
            itemService.updateById(resource);
        }
        return true;
    }

    /**
     * 删除单据
     */
    @PreAuthorize("@ss.hasPermi('maindata:item:remove')")
    @Log(title = "单据", businessType = BusinessType.DELETE)
    @DeleteMapping("/{itemIds}")
    public AjaxResult remove(@PathVariable List<Long> itemIds) {
        ItemQuery query = new ItemQuery();
        query.setIds(new HashSet<>(itemIds));
        List<Item> list = itemService.list(WhereEntityTool.invoke(query));
        list.forEach(x -> {
            if (x.getApprovalStatus() != ApprovalDescriptionEnum.A) {
                throw new ServiceException("E01:单据审核中或已审核，无法删除！");
            }
        });
        return toAjax(itemService.removeByIds(itemIds));
    }
}
